import Base from './Base';
import DrawRect from './DrawRect';
import DrawImage from './DrawImage';
import DrawTextRect from './DrawTextRect';
import moment from 'moment';
import { BaseProps, MapIF, FillRectangleProps } from '../interface';
import CONFIG from '../config';

interface props {
  oVideo: HTMLMediaElement;
  canvasConfig: BaseProps;
  images: Array<string>;
  startTime: string;
  propsAudioPlayingFuc: Function;
  propsAudioCanvasClickFuc: Function;
  YYYYMMDDStartTime: string;
  handleMouseRightClick: Function;
  dpr: number;
  imgScaleX: number;
}

export default class Game extends Base {
  props: props;
  paintList: MapIF<string, any>;
  imageUrls: Array<string>;
  oVideo: HTMLMediaElement;
  startTime: string;
  propsAudioPlayingFuc: Function;
  propsAudioCanvasClickFuc: Function;
  YYYYMMDDStartTime: string;
  handleMouseRightClick: Function;
  realCutOffLineData: BaseProps;
  hoverCutOffLineData: BaseProps;
  hoverTimeGraphData: FillRectangleProps;
  dpr: number;
  imgScaleX: number;

  constructor(props: props) {
    super(props.canvasConfig);
    this.props = props;
    this.dpr = props.dpr || 1;
    this.oVideo = props.oVideo;
    this.imageUrls = props.images;
    this.startTime = props.startTime;
    this.propsAudioPlayingFuc = props.propsAudioPlayingFuc;
    this.propsAudioCanvasClickFuc = props.propsAudioCanvasClickFuc;
    this.YYYYMMDDStartTime = props.YYYYMMDDStartTime;
    this.handleMouseRightClick = props.handleMouseRightClick;
    this.imgScaleX = props.imgScaleX;

    this.paintList = new Map();
    this.realCutOffLineData = this.cutOffLine(CONFIG.canvasRealCutOffLineId, 0);
    this.hoverCutOffLineData = this.cutOffLine(
      CONFIG.canvasHoverCutOffLineId,
      -200
    );
    this.hoverTimeGraphData = this.hoverTimeGraph(
      CONFIG.canvasHoverTimeGraphId,
      -200,
      '15:33:33/00:12:40'
    );
  }

  cutOffLine(id: string, x: number) {
    return {
      id,
      x,
      y: 0,
      width: CONFIG.canvasCutOffLineWidth,
      height: this.height,
      bgColor: CONFIG.canvasCutOffLineColor
    };
  }

  hoverTimeGraph(id: string, x: number, text: string): FillRectangleProps {
    return {
      id,
      x: x + 10,
      y: 10,
      width: CONFIG.canvasHoverTimeGraphWidth,
      height: CONFIG.canvasHoverTimeGraphHeight,
      bgColor: CONFIG.canvasHoverTimeGraphBgColor,
      text,
      maxWidth: CONFIG.canvasHoverTimeGraphWidth,
      font: '13px PingFangSC-Medium',
      lineHeight: 18,
      fontColor: '#FFFFFF',
      textBaseline: 'top',
      paddingTop: 0,
      paddingLeft: 0
    };
  }

  lastTime() {
    return this.computedHoverTextGraphTimeText(this.width);
  }

  jumpLeft(time: number) {
    const currentTime = this.currentTime();
    if (currentTime - time < 0) {
      this.setCurrentTime(0);
      return {
        relativeTime: this.YYYYMMDDStartTime,
        absoluteTime: '00:00:00'
      };
    } else {
      this.setCurrentTime(currentTime - time);
      return this.computedNumberTimeToReturnTime(currentTime - time);
    }
  }

  jumpRight(time: number) {
    const currentTime = this.currentTime();
    if (currentTime + time > this.oVideo.duration) {
      this.setCurrentTime(this.oVideo.duration);
      return this.computedNumberTimeToReturnTime(this.oVideo.duration);
    } else {
      this.setCurrentTime(currentTime + time);
      return this.computedNumberTimeToReturnTime(currentTime + time);
    }
  }

  setPlaybackRate(number: number = 1) {
    this.oVideo.playbackRate = number;
  }

  setVolume(number: number = 1) {
    this.oVideo.volume = number;
  }

  onLoadImg(imageUrl: string) {
    const img = new Image();
    img.src = imageUrl;
    img.setAttribute('crossOrigin', 'Anonymous');
    return new Promise((resolve, reject) => {
      img.onload = () => {
        resolve(img);
      };
      img.onerror = () => {
        reject();
      };
    });
  }

  async initImages() {
    const res = (await Promise.all(
      this.imageUrls.map(async item => await this.onLoadImg(item))
    )) as any;
    let x = 0;
    res.forEach((img: HTMLImageElement, index: number) => {
      this.paintList.set(`${index}`, {
        obj: new DrawImage({
          baseProps: {
            id: `img-${index}`,
            x,
            y: 0,
            width: Math.floor(this.imgScaleX * img.width),
            height: img.height,
            bgColor: '#FFFFFF'
          },
          img
        })
      });
      x += Math.floor(this.imgScaleX * img.width);
    });
  }

  play() {
    this.oVideo.play();
  }

  pause() {
    this.oVideo.pause();
  }

  paused() {
    return this.oVideo.paused;
  }

  computedNumberTimeToReturnTime(time: number) {
    return {
      relativeTime: moment(this.YYYYMMDDStartTime, 'YYYY-MM-DD HH:mm:ss')
        .add(time, 's')
        .format('YYYY-MM-DD HH:mm:ss'),
      absoluteTime: moment('00:00:00', 'HH:mm:ss')
        .add(time, 's')
        .format('HH:mm:ss')
    };
  }

  setCurrentTime(time: number) {
    this.oVideo.currentTime = time;
    return this.computedNumberTimeToReturnTime(time);
  }

  currentTime() {
    return this.oVideo.currentTime;
  }

  cutOffCanvasColor() {
    const x = this.paintList.get(CONFIG.canvasRealCutOffLineId).obj.x;
    if (x >= 1) {
      const canvasData = this.ctx.getImageData(
        0,
        0,
        x * this.dpr,
        this.height * this.dpr
      );
      const rgbaData = canvasData.data;
      for (let i = 0, len = rgbaData.length / 4; i < len; i++) {
        // rgbaData[i * 4] = 255 - rgbaData[i * 4];
        // rgbaData[i * 4 + 1] = 255 - rgbaData[i * 4 + 1];
        // rgbaData[i * 4 + 2] = 255 - rgbaData[i * 4 + 2];
        rgbaData[i * 4 + 3] = rgbaData[i * 4 + 3] * 0.3;
      }
      this.ctx.putImageData(canvasData, 0, 0);
    }
  }

  // 计算当前进度条 -> x位置
  computedCurrentX() {
    const percentage = this.currentTime() / this.oVideo.duration;
    return Math.floor(this.width * percentage);
  }

  // 计算当前hover位置 -> 时间信息
  computedHoverTextGraphTimeText(x: number) {
    const percentage = x / this.width;
    const fromZero = Math.floor(this.oVideo.duration * percentage);
    return {
      fromZeroTime: moment('00:00:00', 'HH:mm:ss')
        .add(fromZero, 's')
        .format('HH:mm:ss'),

      fromStartTimeTime: moment(this.startTime, 'HH:mm:ss')
        .add(fromZero, 's')
        .format('HH:mm:ss'),
      fromYYYYMMDDStartTime: moment(
        this.YYYYMMDDStartTime,
        'YYYY-MM-DD HH:mm:ss'
      )
        .add(fromZero, 's')
        .format('YYYY-MM-DD HH:mm:ss'),
      fromZero
    };
  }

  eventPlay(propsAudioPlayingFuc: Function) {
    this.oVideo.addEventListener('timeupdate', e => {
      const x = this.computedCurrentX();
      this.paintList.get(CONFIG.canvasRealCutOffLineId).obj.x = x;

      propsAudioPlayingFuc(
        this.computedNumberTimeToReturnTime(this.currentTime())
      );
      this.paint();
    });
  }

  bindHoverEvent() {
    this.canvas.onmouseenter = ev => {
      const graph = this.paintList.get(CONFIG.canvasHoverTimeGraphId);
      const line = this.paintList.get(CONFIG.canvasHoverCutOffLineId);
      document.onmousemove = ev => {
        const { x } = this.positionInCanvas(ev);
        const { fromZeroTime, fromStartTimeTime } =
          this.computedHoverTextGraphTimeText(x);
        graph.obj.x =
          x > this.width / 2 ? x - CONFIG.canvasHoverTimeGraphWidth : x;
        line.obj.x = x;
        graph.obj.text = `${fromStartTimeTime}/${fromZeroTime}`;
        this.paint();
      };
      this.canvas.onmouseleave = ev => {
        graph.obj.x = -200;
        line.obj.x = -200;
        this.paint();

        document.onmousemove = null;
        this.canvas.onmouseleave = null;
      };
    };
  }

  bindLeftClickEvent() {
    this.canvas.onclick = ev => {
      const { button } = ev;
      if (![0, 1].includes(button)) return;
      const { x } = this.positionInCanvas(ev);
      const numberTime = this.computedHoverTextGraphTimeText(x).fromZero;
      this.setCurrentTime(numberTime);
      this.propsAudioCanvasClickFuc(
        this.computedNumberTimeToReturnTime(numberTime)
      );
    };
  }

  bindRightClickEvent() {
    this.canvas.oncontextmenu = ev => {
      ev.preventDefault();
      const { x } = this.positionInCanvas(ev);
      this.handleMouseRightClick(this.computedHoverTextGraphTimeText(x));
    };
  }

  async initGraphs() {
    this.paintList.set('background', {
      obj: new DrawRect(this.props.canvasConfig)
    });
    await this.initImages();
    this.paintList.set(CONFIG.canvasRealCutOffLineId, {
      obj: new DrawRect(this.realCutOffLineData)
    });
    this.paintList.set(CONFIG.canvasHoverTimeGraphId, {
      obj: new DrawTextRect(this.hoverTimeGraphData)
    });
    this.paintList.set(CONFIG.canvasHoverCutOffLineId, {
      obj: new DrawRect(this.hoverCutOffLineData)
    });
  }

  async init() {
    await this.initGraphs();
    this.setVolume();
    this.eventPlay(this.propsAudioPlayingFuc);
    this.paint();
    this.bindHoverEvent();
    this.bindLeftClickEvent();
    this.bindRightClickEvent();
  }

  // 画布
  paint() {
    const { ctx, paintList, width, height } = this;
    ctx.clearRect(0, 0, width, height);
    paintList.forEach(value => {
      value.obj.paint();
    });
    this.cutOffCanvasColor();
  }
}